package com.cema.manage.project.manage.adRecord.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.cema.manage.project.enums.CallbackAdRecordEnum;
import com.cema.manage.project.manage.adRecord.domain.AdRecord;
import com.cema.manage.project.manage.adRecord.domain.AdRecordHourVo;
import com.cema.manage.project.manage.adRecord.domain.AdRecordVo;
import com.cema.manage.project.manage.adRecord.domain.RankListVo;
import com.cema.manage.project.manage.adRecord.mapper.AdRecordMapper;
import com.cema.manage.project.manage.adRecordSecondary.domain.AdRecordSecondary;
import com.cema.manage.project.manage.adRecordSecondary.mapper.AdRecordSecondaryMapper;
import com.cema.manage.project.system.user.domain.UsersLogin;
import com.cema.manage.project.util.DateUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 广告记录 服务层实现
 *
 * @author reasahi
 * @date 2024-07-26
 */
@Service
public class AdRecordServiceImpl extends ServiceImpl<AdRecordMapper, AdRecord> implements IAdRecordService {

    @Resource
    private AdRecordSecondaryMapper adRecordSecondaryMapper;

    @Override
    public List<RankListVo> getRankList(AdRecordVo adRecordVo) {
        EntityWrapper<AdRecord> entityWrapper = new EntityWrapper<>();
        AdRecord adRecord = BeanUtil.toBean(adRecordVo, AdRecord.class);
        adRecord.setArCallback(CallbackAdRecordEnum.CALLBACK_YES.getValue());
        entityWrapper.setEntity(adRecord);
        EntityWrapper<AdRecordSecondary> entityWrapperSecondary = new EntityWrapper<>();
        AdRecordSecondary adRecordSecondary = new AdRecordSecondary();
        adRecordSecondary.setArsChannel(adRecord.getArChannel());
        adRecordSecondary.setUvChannel(adRecord.getUvChannel());
        entityWrapperSecondary.setEntity(adRecordSecondary);
        Date start = adRecordVo.getStartTime();
        if (ObjectUtil.isNotNull(start)) {
            entityWrapper.between("create_time", start, adRecordVo.getEndTime());
            entityWrapperSecondary.between("create_time", start, adRecordVo.getEndTime());
        }
        List<AdRecord> adRecordList = selectList(entityWrapper);
        if (ObjectUtil.isNull(adRecordList)) {
            return new ArrayList<>();
        }
        List<AdRecordSecondary> adRecordSecondaryList = adRecordSecondaryMapper.selectList(entityWrapperSecondary);
        // 分组求和
        List<RankListVo> rankingLists = new ArrayList<>();
        switch (adRecordVo.getIndex()) {
            case 1:
                setUsersData(adRecordList, rankingLists, adRecordSecondaryList);
                break;
            case 2:
                setUsersDataFu(adRecordList, rankingLists, adRecordSecondaryList);
                break;
            case 3:
                setUsersDataHome(adRecordList, rankingLists, adRecordSecondaryList);
                break;
            default:
                break;
        }
        return rankingLists;
    }

    @Override
    public Map<String, Object> getHour(AdRecordHourVo adRecordHourVo) {
        Map<String, Object> map = new HashMap<>(3);
        EntityWrapper<AdRecord> entityWrapper = new EntityWrapper<>();
        EntityWrapper<AdRecordSecondary> entityWrapperSecondary = new EntityWrapper<>();
        String channel = adRecordHourVo.getChannel();
        if (StrUtil.isNotEmpty(channel)) {
            entityWrapper.eq("ar_channel", channel);
            entityWrapperSecondary.eq("ars_channel", channel);
        }
        Integer usId = adRecordHourVo.getUsId();
        if (ObjectUtil.isNotNull(usId)) {
            entityWrapper.eq("us_id", usId);
            entityWrapperSecondary.eq("us_id", usId);
        }
        String createTime = adRecordHourVo.getCreateTime();
        if (StrUtil.isNotEmpty(createTime)) {
            DateUtils.getCurrentDayTime(entityWrapper, createTime, "create_time");
            DateUtils.getCurrentDayTime(entityWrapperSecondary, createTime, "create_time");
        }
        List<AdRecord> adRecordList = selectList(entityWrapper);
        int adRecordSum = 0;
        if (ObjectUtil.isNotNull(adRecordList) && adRecordList.size() > 0) {
            adRecordSum = adRecordList.stream().mapToInt(AdRecord::getArRealityMoney).sum();
        }
        map.put("adRecordSum", adRecordSum);
        List<AdRecordSecondary> adRecordSecondaryList = adRecordSecondaryMapper.selectList(entityWrapperSecondary);
        int adRecordSecondarySum = 0;
        if (ObjectUtil.isNotNull(adRecordSecondaryList) && adRecordSecondaryList.size() > 0) {
            adRecordSecondarySum = adRecordSecondaryList.stream().mapToInt(AdRecordSecondary::getArsRealityMoney).sum();
        }
        map.put("adRecordSecondarySum", adRecordSecondarySum);
        // 你可以传入任意的日期
        Date inputDate = new Date();
        List<DateUtils.TimeRange> timeRanges = DateUtils.get24HourTimeRanges(inputDate);
        List<UsersLogin> usersLoginList = new ArrayList<>();
        for (DateUtils.TimeRange timeRange : timeRanges) {
            UsersLogin ulrLogin = new UsersLogin();
            // LocalDateTime转Date
            Date start = Date.from(timeRange.getStartTime().atZone(ZoneId.systemDefault()).toInstant());
            Date end = Date.from(timeRange.getEndTime().atZone(ZoneId.systemDefault()).toInstant());
            String formatDate = DateUtil.format(start, "yyyy-MM-dd HH:mm");
            int aSum = 0;
            int bSum = 0;
            List<AdRecord> adRecords =
                    adRecordList.stream().filter(adRecord -> adRecord.getCreateTime().compareTo(start) >= 0 && adRecord.getCreateTime().compareTo(end) <= 0).collect(Collectors.toList());
            if (ObjectUtil.isNotNull(adRecords) && adRecords.size() > 0) {
                aSum = adRecords.stream().mapToInt(AdRecord::getArRealityMoney).sum();
            }
            List<AdRecordSecondary> adRecordSecondaries =
                    adRecordSecondaryList.stream().filter(adRecordSecondary -> adRecordSecondary.getCreateTime().compareTo(start) >= 0 && adRecordSecondary.getCreateTime().compareTo(end) <= 0).collect(Collectors.toList());
            if (ObjectUtil.isNotNull(adRecordSecondaries) && adRecordSecondaries.size() > 0) {
                bSum = adRecordSecondaries.stream().mapToInt(AdRecordSecondary::getArsRealityMoney).sum();
            }
            ulrLogin.setA(aSum);
            ulrLogin.setB(bSum);
            ulrLogin.setY(formatDate);
            usersLoginList.add(ulrLogin);
        }
        map.put("adRecordList", usersLoginList);
        return map;
    }

    /**
     * 封装数据
     *
     * @param adRecordList
     * @param rankListVoList
     */
    private void setUsersData(List<AdRecord> adRecordList, List<RankListVo> rankListVoList, List<AdRecordSecondary> adRecordSecondaryList) {
        Map<Integer, Integer> groupSum = adRecordList.stream().collect(Collectors.groupingBy(AdRecord::getUsId, Collectors.summingInt(AdRecord::getArRealityMoney)));
        Map<Integer, Integer> groupSumArs = adRecordSecondaryList.stream().collect(Collectors.groupingBy(AdRecordSecondary::getUsId, Collectors.summingInt(AdRecordSecondary::getArsRealityMoney)));
        List<AdRecord> parentAdRecordList = adRecordList.stream().filter(adRecord -> ObjectUtil.isNotNull(adRecord.getUsParentId())).collect(Collectors.toList());
        // 排序（升序）
        List<Map.Entry<Integer, Integer>> sortedGroupSum = groupSum.entrySet().stream()
                .sorted(Map.Entry.comparingByKey())
                .collect(Collectors.toList());
        Collections.sort(sortedGroupSum, ((o1, o2) -> o2.getValue().compareTo(o1.getValue())));
        sortedGroupSum.forEach(entry -> {
            RankListVo rankListVo = new RankListVo();
            int value = groupSumArs.get(entry.getKey());
            int adCountMoney = value + entry.getValue();
            rankListVo.setAdCountMoney(String.valueOf(adCountMoney));
            //sumGroup.put(entry.getKey(), value + entry.getValue());
            rankListVo.setId(String.valueOf(entry.getKey()));
            int index = rankListVoList.size() + 1;
            rankListVo.setIndex(String.valueOf(index));
            rankListVo.setMoney(String.valueOf(entry.getValue()));
            if (ObjectUtil.isNotNull(parentAdRecordList) && parentAdRecordList.size() > 0) {
                Optional<AdRecord> parentAdRecord = parentAdRecordList.stream().filter(adRecord -> adRecord.getUsId().equals(entry.getKey())).findFirst();
                if (parentAdRecord.isPresent()) {
                    AdRecord record = parentAdRecord.get();
                    rankListVo.setParenId(String.valueOf(record.getUsParentId()));
                }
            }
            long count = adRecordList.stream().filter(adRecord -> entry.getKey().equals(adRecord.getUsId())).count();
            long secondaryCount = adRecordSecondaryList.stream().filter(adRecordSecondary -> entry.getKey().equals(adRecordSecondary.getUsId())).count();
            rankListVo.setSecondaryCount(String.valueOf(secondaryCount));
            int secondaryMoney = adRecordSecondaryList.stream().filter(adRecordSecondary -> entry.getKey().equals(adRecordSecondary.getUsId())).mapToInt(AdRecordSecondary::getArsRealityMoney).sum();
            rankListVo.setSecondaryMoney(String.valueOf(secondaryMoney));
            rankListVo.setCount(String.valueOf(count));
            long adCount = count + secondaryCount;
            rankListVo.setAdCount(String.valueOf(adCount));
            rankListVoList.add(rankListVo);
        });
    }

    /**
     * 封装数据
     *
     * @param adRecordList
     * @param rankListVoList
     */
    private void setUsersDataFu(List<AdRecord> adRecordList, List<RankListVo> rankListVoList, List<AdRecordSecondary> adRecordSecondaryList) {
        Map<Integer, Integer> groupSum = adRecordSecondaryList.stream().collect(Collectors.groupingBy(AdRecordSecondary::getUsId, Collectors.summingInt(AdRecordSecondary::getArsRealityMoney)));
        Map<Integer, Integer> groupSumArs = adRecordList.stream().collect(Collectors.groupingBy(AdRecord::getUsId, Collectors.summingInt(AdRecord::getArRealityMoney)));
        List<AdRecord> parentAdRecordList = adRecordList.stream().filter(adRecord -> ObjectUtil.isNotNull(adRecord.getUsParentId())).collect(Collectors.toList());
        // 排序（升序）
        List<Map.Entry<Integer, Integer>> sortedGroupSum = groupSum.entrySet().stream()
                .sorted(Map.Entry.comparingByKey())
                .collect(Collectors.toList());
        Collections.sort(sortedGroupSum, ((o1, o2) -> o2.getValue().compareTo(o1.getValue())));
        sortedGroupSum.forEach(entry -> {
            RankListVo rankListVo = new RankListVo();
            int value = 0;
            if (groupSumArs.containsKey(entry.getKey())) {
                value = groupSumArs.get(entry.getKey());
            }
            int adCountMoney = value + entry.getValue();
            rankListVo.setAdCountMoney(String.valueOf(adCountMoney));
            rankListVo.setId(String.valueOf(entry.getKey()));
            int index = rankListVoList.size() + 1;
            rankListVo.setIndex(String.valueOf(index));
            rankListVo.setSecondaryMoney(String.valueOf(entry.getValue()));
            if (ObjectUtil.isNotNull(parentAdRecordList) && parentAdRecordList.size() > 0) {
                Optional<AdRecord> parentAdRecord = parentAdRecordList.stream().filter(adRecord -> adRecord.getUsId().equals(entry.getKey())).findFirst();
                if (parentAdRecord.isPresent()) {
                    AdRecord record = parentAdRecord.get();
                    rankListVo.setParenId(String.valueOf(record.getUsParentId()));
                }
            }
            long count = adRecordList.stream().filter(adRecord -> entry.getKey().equals(adRecord.getUsId())).count();
            long secondaryCount = adRecordSecondaryList.stream().filter(adRecordSecondary -> entry.getKey().equals(adRecordSecondary.getUsId())).count();
            rankListVo.setSecondaryCount(String.valueOf(secondaryCount));
            int money = adRecordList.stream().filter(adRecordSecondary -> entry.getKey().equals(adRecordSecondary.getUsId())).mapToInt(AdRecord::getArRealityMoney).sum();
            rankListVo.setMoney(String.valueOf(money));
            rankListVo.setCount(String.valueOf(count));
            long adCount = count + secondaryCount;
            rankListVo.setAdCount(String.valueOf(adCount));
            rankListVoList.add(rankListVo);
        });
    }

    /**
     * 封装数据
     *
     * @param adRecordList
     * @param rankListVoList
     */
    private void setUsersDataHome(List<AdRecord> adRecordList, List<RankListVo> rankListVoList, List<AdRecordSecondary> adRecordSecondaryList) {
        Map<Integer, Integer> groupSum = adRecordList.stream().collect(Collectors.groupingBy(AdRecord::getUsId, Collectors.summingInt(AdRecord::getArRealityMoney)));
        Map<Integer, Integer> groupSumArs = adRecordSecondaryList.stream().collect(Collectors.groupingBy(AdRecordSecondary::getUsId, Collectors.summingInt(AdRecordSecondary::getArsRealityMoney)));
        Map<Integer, Integer> sumGroup = new HashMap<>();
        for (Map.Entry<Integer, Integer> entry : groupSum.entrySet()) {
            int value = 0;
            if (groupSumArs.containsKey(entry.getKey())) {
                value = groupSumArs.get(entry.getKey());
            }
            sumGroup.put(entry.getKey(), value + entry.getValue());
        }
        List<AdRecord> parentAdRecordList = adRecordList.stream().filter(adRecord -> ObjectUtil.isNotNull(adRecord.getUsParentId())).collect(Collectors.toList());
        // 排序（升序）
        List<Map.Entry<Integer, Integer>> sortedGroupSum = sumGroup.entrySet().stream()
                .sorted(Map.Entry.comparingByKey())
                .collect(Collectors.toList());
        Collections.sort(sortedGroupSum, ((o1, o2) -> o2.getValue().compareTo(o1.getValue())));
        sortedGroupSum.forEach(entry -> {
            RankListVo rankListVo = new RankListVo();
            rankListVo.setId(String.valueOf(entry.getKey()));
            int index = rankListVoList.size() + 1;
            rankListVo.setIndex(String.valueOf(index));
            rankListVo.setAdCountMoney(String.valueOf(entry.getValue()));
            if (ObjectUtil.isNotNull(parentAdRecordList) && parentAdRecordList.size() > 0) {
                Optional<AdRecord> parentAdRecord = parentAdRecordList.stream().filter(adRecord -> adRecord.getUsId().equals(entry.getKey())).findFirst();
                if (parentAdRecord.isPresent()) {
                    AdRecord record = parentAdRecord.get();
                    rankListVo.setParenId(String.valueOf(record.getUsParentId()));
                }
            }
            int money = adRecordList.stream().filter(adRecordSecondary -> entry.getKey().equals(adRecordSecondary.getUsId())).mapToInt(AdRecord::getArRealityMoney).sum();
            rankListVo.setMoney(String.valueOf(money));
            long count = adRecordList.stream().filter(adRecord -> entry.getKey().equals(adRecord.getUsId())).count();
            long secondaryCount = adRecordSecondaryList.stream().filter(adRecordSecondary -> entry.getKey().equals(adRecordSecondary.getUsId())).count();
            rankListVo.setSecondaryCount(String.valueOf(secondaryCount));
            int secondaryMoney = adRecordSecondaryList.stream().filter(adRecordSecondary -> entry.getKey().equals(adRecordSecondary.getUsId())).mapToInt(AdRecordSecondary::getArsRealityMoney).sum();
            rankListVo.setSecondaryMoney(String.valueOf(secondaryMoney));
            rankListVo.setCount(String.valueOf(count));
            long adCount = count + secondaryCount;
            rankListVo.setAdCount(String.valueOf(adCount));
            rankListVoList.add(rankListVo);
        });
    }
}
